package world.criver.mm_vworld_server.function;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import world.criver.crc.CRC;
import world.criver.mm_vworld_server.config.conConfig;
import world.criver.mm_vworld_server.data.daServer;
import world.criver.mm_vworld_server.modular.moClient;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

@Component
public class funServer {
    @Autowired
    private conConfig conConfig;
    @Autowired
    private funClientMessageHandle funClientMessageHandle;

    private CRC crc = new CRC();
    /**
     * 启动服务器
     */
    public boolean start(){
        try {
            daServer.server = new ServerSocket(conConfig.getServerPort());
            daServer.server_listen=Thread.startVirtualThread(new listen());
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 停止服务器
     */
    public boolean stop(){
        try{
            if(daServer.server==null || daServer.server.isClosed())return true;
            daServer.server.close();
            moClient mo;
            for(String ip:daServer.clients.keySet()){
                mo=daServer.clients.get(ip);
                mo.getWriter().close();
                mo.getReceiver().interrupt();
                mo.getClient().close();
            }
            daServer.clients.clear();
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 断开客户端
     * @param id
     * @return
     */
    public boolean stopClient(String id){
        try{
            if(daServer.server==null || daServer.server.isClosed())return true;
            if(!daServer.clients.containsKey(id))return false;
            moClient mo=daServer.clients.get(id);
            mo.getWriter().close();
            mo.getReceiver().interrupt();
            mo.getClient().close();
            daServer.clients.remove(id);
            System.out.println("close:"+id+"\t"+daServer.clients.size());
            return true;
        }catch (Exception e){
            return false;
        }
    }
    public class listen implements Runnable{

        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()){
                try {
                    Socket client = daServer.server.accept();
                    String ip=client.getInetAddress().getHostAddress();
                    System.out.println(ip);
                    if(daServer.clients.containsKey(ip)){
                        client.close();
                        continue;
                    }
                    System.out.println(ip+">>connect");
                    Thread receiver=Thread.ofVirtual().unstarted(new client_receiver(ip));
                    moClient mc=new moClient();
                    mc.setIp(ip);
                    mc.setClient(client);
                    mc.setReceiver(receiver);
                    daServer.clients.put(ip,mc);
                    receiver.start();
                }catch (Exception e){
                    throw new RuntimeException(e);
                }
            }
        }
    }
    public class client_receiver implements Runnable{
        private String id;
        public client_receiver(String id){
            this.id=id;
        }

        @Override
        public void run() {
            try {
                BufferedReader re = new BufferedReader(new InputStreamReader(daServer.clients.get(id).getClient().getInputStream()));
                while (!Thread.currentThread().isInterrupted()) {
                    String line=re.readLine();
                    if(line==null||line.isEmpty())continue;
                    line= crc.decrypt(conConfig.getEncryptKey(), line);
                    funClientMessageHandle.handle(id,line);
                }
            }catch (SocketException e){
                stopClient(id);
            }catch (Exception e){
                throw new RuntimeException(e);
            }
        }
    }
}
